<template lang="pug">
  .main
    .table-top.clearfix
      ButtonList(
        v-if="toolbarList && toolbarList.length > 0"
        class="toolbar"
        :buttonList="toolbarList")
      slot(
        class="customToolbar"
        name="toolbar")
      FilterBox(
        v-if="filterList && filterList.length > 0 && isFilterShow"
        class="filter-box"
        :columns="columnsList"
        :filterList="filterList"
        :filterBy="filterBy"
        @changeFilterBy="changeFilterBy")
    DataTable(
      ref="dataTable"
      class="table-wrapper"
      :cid="cid"
      :pid="pid"
      :isTree="isTree"
      :isLoading="isLoading"
      :mainColumn="mainColumn"
      :longColumn="longColumn"
      :clientWidth="clientWidth"
      :clientHeight="clientHeight"
      :tableWrapperWidth="tableWrapperWidth"
      :fullTableWidth="fullTableWidth"
      :tableList="tableList"
      :operationList="operationList"
      :operationWidth="operationWidth"
      :columns="columnsList"
      :tableData="tableData"
      :orderBy="orderBy"
      :isExpand="isExpand"
      @changeOrderBy="changeOrderBy"
      @changeTreeExpands="changeTreeExpands")
    .table-footer
      ColumnFilter(
        class="column-filter"
        :columnsObject="columnsList"
        :tableList="tableInitList"
        :columnGroupBy="columnGroupBy"
        :tableFullList="tableFullList"
        :openDirection=2
        @grandSonEvent="changeTableList")
      .page(v-if="!isTree")
        slot(name="info")
        el-pagination(
          class="pagination"
          layout="total, sizes, prev, pager, next"
          :page-sizes="[10, 25, 50, 100]"
          :page-size="pageSize"
          :current-page="pageIndex"
          :total="recordsFiltered"
          @size-change="pageSizeChange"
          @current-change="pageIndexChange")
    SmartDialog(
      v-if="dialogShow"
      v-model="dialogVisible"
      :title="dialogLabel"
      :size="dialogSize")
      SmartForm(
        class="dialogform"
        labelPosition="right"
        :formList="dialogFormList"
        :values="dialogFormValues"
        :columns="columnsList"
        :buttonList="dialogButtonList"
        :formEnterIndex="0")
    PrintTable(
      ref="print"
      :title="title"
      :printList="tableList"
      :dataList="tableData"
      :columns="columnsList"
      :isHorizontal="isHorizontal")
    ExcelTable(
      ref="export"
      :title="title"
      :exportList="tableList"
      :dataList="tableData"
      :columns="columnsList"
      :isTime="isTime")
    slot
</template>
<script>

import { mapGetters, mapMutations } from 'vuex'
import { cloneDeep } from 'lodash'
import { treeFormat, valueFormat } from '@/utils/common'

import SmartDialog from '@/components/SmartDialog'
import SmartForm from '@/components/SmartForm'
import DataTable from '@/components/DataTable'
import ButtonList from '@/components/ButtonList'
import FilterBox from '@/components/FilterBox'
import ColumnFilter from '@/containers/DataTablePage/columnFilter'
import PrintTable from '@/components/PrintTable'
import ExcelTable from '@/components/ExcelTable'

export default {
  name: 'DataTablePage',
  components: {
    SmartDialog,
    SmartForm,
    DataTable,
    ButtonList,
    FilterBox,
    ColumnFilter,
    PrintTable,
    ExcelTable
  },
  props: {
    isTree: {
      type: Boolean,
      default: false
    },
    resource: {
      type: String,
      default: ''
    }, /* 标题英文名 */
    title: {
      type: String,
      default: ''
    }, /* 标题英文名 */
    label: {
      type: String,
      default: 'label'
    }, /* 标题英文名 */
    labelName: {
      type: String,
      default: 'label'
    },
    dialogSize: String,
    toolbar: {
      type: Array,
      default: () => ([])
    },
    operation: {
      type: Array,
      default: () => ([])
    },
    operationWidth: {
      type: Number,
      default: 200
    },
    cid: {
      type: String,
      default: 'id'
    }, /* 页面对话框标题 */
    pid: {
      type: String,
      default: 'pid'
    }, /* 页面对话框标题 */
    mainColumn: {
      type: String,
      default: 'label'
    }, /* 标题英文名 */
    longColumn: {
      type: String,
      default: 'label'
    }, /* 标题英文名 */
    columns: {
      type: Object,
      default: () => ({})
    },
    tableFullList: {
      type: Array,
      default: () => ([])
    },
    tableInitList: {
      type: Array,
      default: () => ([])
    },
    filterFullList: {
      type: Array,
      default: () => ([])
    },
    filterInitList: {
      type: Array,
      default: () => ([])
    },
    printList: {
      type: Array,
      default: () => ([])
    },
    createList: {
      type: Array,
      default: () => ([])
    },
    updateList: {
      type: Array,
      default: () => ([])
    },
    createFormValues: {
      type: Object,
      default: () => ({})
    },
    filterByAlways: {
      type: Object,
      default: () => ({})
    },
    filterByInit: {
      type: Object,
      default: () => ({})
    },
    orderByInit: {
      type: Array,
      default: () => ([])
    },
    columnGroupBy: {
      type: Array,
      default: () => []
    },
    formLabelWidth: {
      type: Number,
      default: 140
    },
    tableWidth: {
      type: Number,
      default: 0
    },
    fullTableWidth: {
      type: Boolean,
      default: false
    }, // dataTable 100%宽度
    isExpand: Function,
    requestData: {
      type: Object,
      default: () => {
        return {}
      }
    }, // dataTable 分页获取添加请求参数
    isHorizontal: {
      type: Boolean,
      default: true
    }, // 打印是否横向处理, 默认横向处理
    isTime: {
      type: Boolean,
      default: true
    } // 导出的文件名是否添加时间, 默认添加
  },
  data () {
    // 字段信息
    const columnsList = cloneDeep(this.columns)
    columnsList.serial = {
      label: '序号',
      width: 64,
      // type: 'custom',
      render ({index}) {
        return index + 1
      }
    }
    const columnsKeys = Object.keys(columnsList)
    columnsKeys.map(key => {
      columnsList[key].width = columnsList[key].width || 200
    })
    const relationKeys = columnsKeys.filter(key => columnsList[key].relation).map(key => columnsList[key].relation)
    const that = this
    const pagePath = this.$route.path
    const pageStorage = this.$store.getters.pageStorage[pagePath] || {}
    const { tableList, filterBy, orderBy, pageSize, pageIndex } = pageStorage
    return {
      pagePath,
      tableList: tableList || this.tableInitList,
      filterList: this.filterInitList,
      isFilterShow: !relationKeys.length,
      relationKeys: relationKeys,
      tableData: [],
      dialogVisible: false,
      columnsList: columnsList,
      filterBy: filterBy || [],
      orderBy: orderBy || [],
      treeExpands: new Set(),
      pageSize: pageSize || 10,
      pageIndex: pageIndex || 1,
      recordsFiltered: 0,
      recordsTotal: 0,
      isLoading: false,
      createButtonList: [{
        name: 'submit',
        label: '提交',
        type: 'complete',
        validate: true,
        funcProps: {
          table: this
        },
        func ({funcProps}) {
          const { table, form, button } = funcProps
          button.loading = true
          table.$post({
            url: table.resource,
            data: form.formValues
          }).then(data => {
            button.loading = false
            if (data) {
              table.getData()
              table.dialogVisible = false
            }
          })
        }
      }],
      updateButtonList: [{
        name: 'submit',
        label: '提交',
        type: 'complete',
        validate: true,
        funcProps: {
          table: this
        },
        func ({funcProps}) {
          const { form, button } = funcProps
          button.loading = true
          this.$put({
            url: `${that.resource}/${form.formValues.id}`,
            data: form.formValues
          }).then(data => {
            button.loading = false
            if (data) {
              that.getData()
              that.dialogVisible = false
            }
          })
        } /* 编辑表单的提交事件 */
      }]
    }
  },
  mounted () {
    this.relationKeys.length ? this.getRelation() : this.getData()
  },
  computed: {
    ...mapGetters([
      'menuActive',
      'clientWidth',
      'clientHeight'
    ]), /* navbar状态获取,影响table宽度 */
    tableWrapperWidth () {
      if (this.tableWidth) {
        return this.tableWidth
      }
      return this.clientWidth - (this.menuActive ? 210 : 0) - ((this.clientWidth > 991) ? 70 : 0) - 40
    }, /* 影响table宽度计算，和navbar状态相关 */
    dialogShow () {
      return this.dialogVisible
    }, /* 判断新增弹窗是否打开 */
    updateDialogShow () {
      return this.updateDialogVisible
    }, /* 判断编辑弹窗是否打开 */
    operationList () {
      return this.operation.map(item => {
        return {
          ...item,
          size: 'mini',
          funcProps: {
            ...item.funcProps,
            table: this
          }
        }
      })
    }, /* 计算table的操作列 */
    toolbarList () {
      return this.toolbar.map(item => {
        return {
          ...item,
          funcProps: {
            ...item.funcProps,
            table: this
          }
        }
      })
    } /* 计算table的工具栏toolbar */
  },
  methods: {
    ...mapMutations([
      'changePageStorage'
    ]),
    pageSizeChange (value) {
      this.pageSize = value
      this.changePageStorage({
        page: this.pagePath,
        type: 'pageSize',
        value
      })
      this.pageIndexChange(1)
    }, /* 每页显示记录数的修改函数 */
    pageIndexChange (value) {
      this.pageIndex = value
      this.changePageStorage({
        page: this.pagePath,
        type: 'pageIndex',
        value
      })
      this.getData()
    }, /* 当前页码的修改函数 */
    changeOrderBy (value) {
      this.orderBy = value
      this.changePageStorage({
        page: this.pagePath,
        type: 'orderBy',
        value
      })
      this.getData()
    },
    changeFilterBy (value) {
      this.filterBy = value
      this.changePageStorage({
        page: this.pagePath,
        type: 'filterBy',
        value
      })
      this.getData()
    },
    getRelation (value) {
      this.isLoading = true
      this.$getRelation({
        relations: this.relationKeys.join(',')
      }).then((data) => {
        Object.keys(this.columnsList).map(key => {
          const relation = this.columnsList[key].relation
          if (data[relation]) {
            this.columnsList[key].options = [...this.columnsList[key].optionsInit || [], ...data[relation]].map(option => {
              const label = option[this.columnsList[key].labelName || 'label']
              // const subtextKey = this.columnsList[key].subtext || 'subtext'
              // const subtext = subtextKey === 'pinyin' ? pinyinInitial(label) : option[subtextKey]
              return {
                value: option.value !== undefined ? option.value : option.id,
                label,
                // subtext,
                ...option
              }
            })
          }
        })
        this.isLoading = false
        this.isFilterShow = true
        this.$emit('getRelation', this.columnsList)
        this.getData()
      }).catch(() => {
        this.isLoading = false
      })
    }, /* 获取当前资源所关联的数据，并填到对应的列里 */
    getData () {
      this.$refs.dataTable.updateY(0)
      this.tableData = []
      this.isLoading = true
      this.$get({
        url: this.resource,
        params: {
          orderBy: this.orderByToOrderText([...this.orderByInit, ...this.orderBy]),
          filterBy: this.filterByToFilterText([...this.filterBy, ...this.filterByAlways]),
          pageSize: this.isTree ? 999999 : this.pageSize,
          pageIndex: this.isTree ? 1 : this.pageIndex,
          data: this.requestData
        }
      }).then((data) => {
        this.isLoading = false
        const result = data || {
          data: [],
          recordsFiltered: 0,
          recordsTotal: 0
        }
        this.$emit('getData', result)
        this.tableRender({
          ...result
        })
      }).catch(() => {
        this.isLoading = false
      })
    }, /* 获取数据 */
    tableRender (data) {
      this.tableData = this.isTree ? treeFormat(data.data.map(item => ({
        ...item,
        isExpand: this.treeExpands.has(item.id)
      })), this.cid, this.pid) : data.data
      this.recordsFiltered = data.recordsFiltered
      this.recordsTotal = data.recordsTotal
    },
    changeTableList (value) {
      this.changePageStorage({
        page: this.pagePath,
        type: 'tableList',
        value
      })
      this.tableList = value
    }, /* 列过滤 */
    filterByToFilterText (filterBy) {
      return filterBy.map(({name, type, value}) => `${name}|${type}|${value}`).join(';')
    },
    filterTextToFilterBy (filterText) {
      if (!filterText) {
        return []
      }
      return filterText.split(';').map(item => {
        const filter = item.split('|')
        return {
          name: filter[0],
          type: filter[1],
          value: valueFormat(filter[2], this.columnsList[filter[0]].dataType)
        }
      })
    },
    orderByToOrderText (orderBy) {
      return orderBy.map(({name, sort}) => `${name}|${sort}`).join(';')
    },
    orderTextToOrderBy (orderText) {
      if (!orderText) {
        return []
      }
      return orderText.split(';').map(item => {
        const order = item.split('|')
        return {
          name: order[0],
          sort: order[1]
        }
      })
    },
    changeTreeExpands ({recordIndex, id, isExpand}) {
      const data = this.currentData(this.tableData, recordIndex)
      data.isExpand = !data.isExpand
      data.isExpand ? this.treeExpands.add(id) : this.treeExpands.delete(id)
    },
    currentData (tableData, recordIndex) {
      if (recordIndex.length === 1) {
        return tableData[recordIndex[0]]
      } else {
        const newRecordIndex = recordIndex.slice(1, recordIndex.length)
        return this.currentData(tableData[recordIndex[0]].children, newRecordIndex)
      }
    }
  }
}
</script>

<style scoped lang="sass">
.main
  padding: 20px
  display: flex
  flex-direction: column
  flex: 1
  height: 100%
.table-wrapper
  display: flex
  flex-direction: column
  flex: 1
  position: relative
  z-index: 100
.table-fixed
  position: absolute
  right: 0
.table-top
  margin-bottom: 10px
  position: relative
  z-index: 200
  .toolbar
    float: left
    margin-right: 12px
  .filter-box
    float: right
    margin-left: 12px
  .customToolbar
    margin-bottom: 10px
.pagination
  flex: 1
  padding-top: 12px
  text-align: right
.column-filter
  float: left
  padding-top: 12px
.table-footer
  display: flex
  justify-content:  space-between
  align-item: center
  position: relative
  z-index: 300
.dialogform
  padding: 16px
</style>
